const path = require("path")
const fs = require("fs")
const vm = require("vm")

class Module {
  constructor(id) {
    this.id = id // 当前模块的id名
    this.exports = {} // 默认是空对象 导出的结果
  }
}

const _cache = {} // 缓存

const wrapper = [
  "(function (exports, require, module, __dirname, __filename) {\r\n",
  "\r\n})",
]

const extensions = {
  ".js": function (module) {
    // 读取
    let script = fs.readFileSync(module.id, "utf8")
    // 增加函数 还是一个字符串
    let content = wrapper[0] + script + wrapper[1]
    // 让这个字符串函数执行 (node里api)
    let fn = vm.runInThisContext(content) // 这里就会返回一个js函数
    // console.log(fn.toString())
    let __dirname = path.dirname(module.id)
    // 让函数执行
    fn.call(module.exports, module.exports, _require, module, __dirname, module.id)
  },
  ".json": function (module) {
    let script = fs.readFileSync(module.id, "utf8")
    module.exports = JSON.parse(script)
  },
}
const _resolveFilename = function (id) {
  // 将相对路径转化成绝对路径
  let absPath = path.resolve(id)
  //  先判断文件是否存在如果存在
  if (fs.existsSync(absPath)) {
    return absPath
  }
  // 去尝试添加文件后缀 .js .json
  let _extensions = Object.keys(extensions)
  for (let i = 0; i < _extensions.length; i++) {
    let ext = _extensions[i]
    // 判断路径是否存在
    let currentPath = absPath + ext // 获取拼接后的路径
    console.log(currentPath);
    let exits = fs.existsSync(currentPath) // 判断是否存在
    if (exits) {
      return currentPath
    }
  }
  throw new Error("文件不存在")
}

const _require = (id) => {
  //  计算绝对路径
  let filename = _resolveFilename(id)
  //  第一步：如果有缓存，取出缓存
  let cache = _cache[filename]
  if (cache) { // 如果有缓存直接将模块的结果返回
    return cache.exports
  }
  // 第二步：是否为内置模块
  // ...
  // 第三步：生成模块实例，存入缓存
  let module = new Module(filename) // 创建了一个模块
  _cache[filename] = module
  // 第四步：加载模块
  let ext = path.extname(module.id)
  extensions[ext](module)
  return module.exports
}

let str = _require("./a")
console.log(str.a) // hello world
console.log(str.b) // hello nodejs
console.log(str.double(3)) // 6